/*
* 创建类组件
*   创建一个构造函数(类)，要求必须继承 React.Component/PureComponent 这个类
*       + 我们习惯于使用ES6中class创建类
*       + 必须给当前类设置一个 render 方法(放在类的原型上)：在render方法中，返回需要渲染的视图
*
*
* */


// 基于ESM 模块规范导入
// import React ...：把基于 export default 导出的内容获取到
// import {Component, PureComponent}：不是对react进行解构赋值，而是基于 export导出的内容，进行解构赋值

/*
* 基于 extends 实现继承
*   1. 首先基于call继承  React.Component.call(this) // this -> parent 的实例 p
*       function Component(props,context,updater){...}
*       给创建的实例 p 设置四个私有属性：props/context/refs/update
*   2. 在基于原型继承  Parent.prototype.__proto__ === React.Component.prototype
*      实例除了具备 Parent.prototype 提供的方法，还具备 React.Component.prototype 原型上的方法
*          isReactComponent,setState,foreUpdate
*   3. 只要自己设置了 constructor，则内部第一句话一定要执行 super()
* */

/*
* 创建类组件
*   创建一个构造函数(类)
*   + 要求必须继承 React.Component/PureComponent 这个类
*   + 我们习惯于使用ES6中的class创建类(因为方便)
*   + 必须给当前类设置一个render的方法(放在原型上)：在render方法中，返回需要渲染的视图
*
* 从调用类组件 (new Vote({...})) 开始，类组件内部发生的事情
*   1. 初始化属性 && 规则校验
*       先规则校验，校验玩，再处理属性的其他操作
*       方案一：
*           super(props);//会把传递进来的属性挂载到this实例上
*       方案二：
*           即使我们不在 constructor 中处理 (或constructor都没写)，在constructor处理完毕后，React内部也会完成挂载
*           所以在其他函数中，只要保证this是实例，就可以基于 this.props 获取传递的参数
*           + 同样this.props获取的属性对象也是被冻结(只读的)
*   2.  初始化状态：
*       状态：后期修改状态，可以触发视图的更新
*       需要手动初始化，如果我们没有去做相关的处理，则默认会往实例上挂载一个state，初始值是 null => this.state = null
*       ------- 修改状态，控制视图更新
*
*           this.state.xxxx = xxx：这种操作仅仅是修改了状态值，但是无法让视图更新
*           想让视图更新，我们需要基于 React.Component.prototype 提供的方法操作：
*       方案一：this.setState(partialState) 既可以修改局部状态，也可以更新视图
*       方案二：this.forUpdate()  强制更新
*   3.  触发  componentWillMount  周期函数(钩子函数):组件第一次渲染之前
*           此生命周期，目前是不安全的(虽然可以用，但是未来可能要被移除，使用不建议使用)
*           + 控制台会抛出黄色警告(为了不抛出黄色警告：UNSAFE_componentWillMount)
*   4.  render
*   5.  触发  componentDidMount  周期函数(钩子函数):组件第一次渲染完毕
*       + 页面中已经创建了真实的DOM元素
* */

/*
* 组件更新的逻辑(第一种：当修改了状态被修改，组件会更新)
* 1. 触发 shouldComponentUpdate，是否允许更新
*   +
* 2. 触发 componentWillUpdate    周期函数：更新之前
* 3. 修改状态值/属性值(让this.state.xxx 改为最新的值)
* 4. 触发 render 周期函数：组件更新
*       + 按照最新的状态/属性，把返回的jsx编译为 virtualDOM
*       + 和第一次渲染出来的 virtualDOM 进行对比(dom-diff)
*       + 把差异的部分进行渲染(渲染为真实DOM)
* 5. 触发 componentDidUpdate      周期函数：更新完毕
*   特殊情况：如果基于 this.forceUpdate() 强制更新视图，会跳过 shouldComponentUpdate 周期函数的校验，直接从
*       componentWillUpdate 开始进行更新(也就是：视图一定会触发更新)
*
* 组件更新的逻辑(第二种：父组件更新，触发子组件更新)
* 1. 触发 componentWillReceiveProps   周期函数：接受最新属性之前
* 2. 触发 shouldComponentUpdate 周期函数
* 3. 触发 render
* 4. 触发 componentDidUpdate
*
* */
import React, {Component, PureComponent} from "react";
import propTypes from "prop-types";

class Vote extends React.Component {
    // 属性规则校验
    static defaultProps = {
        num: 0
    }
    static propType = {
        title: propTypes.string.isRequired,
    }
    /*初始化状态*/
    state = {
        supNum: 10,
        oppNum: 5
    };

    constructor(props) {
        super(props);
    }

    render() {
        console.log("reander:渲染")
        let {title} = this.props,
            {supNum, oppNum} = this.state

        return <div className={'vote-box'}>
            <div className={'header'}>
                <h2 className={'title'}>{title}</h2>
                <span>{supNum + oppNum}人</span>
            </div>
            <div className={'main'}>
                <p>支持人数：{supNum}人</p>
                <p>反对人数：{oppNum}人</p>
            </div>
            <div>
                <button onClick={() => {
                    this.setState({
                        supNum: supNum + 1
                    })
                }}>支持
                </button>
                <button onClick={() => {
                    this.setState({
                        oppNum: oppNum + 1
                    })
                }}>反对
                </button>
            </div>
        </div>
    }

    UNSAFE_componentWillMount() {
        console.log('componentWillMount：第一次渲染之前')
    }

    componentDidMount() {
        console.log('componentDidMount：第一次渲染完毕')
    }

    shouldComponentUpdate(nextProps, nextState) {
        // nextState：存储要修改的最新状态
        // this.setState：存储的还是修改前的状态(此时状态还没有改变)

        console.log("shouldComponentUpdate", this.state, nextState, '是否允许更新')

        // 此周期函数需要返回 true/false
        //      返回 true：允许更新，会继续执行下一个操作
        //      返回 false：不允许更新，接下来啥都不处理
        return true
    }

    UNSAFE_componentWillUpdate(nextProps, nextState) {
        console.log('componentWillUpdate', this.state, nextState, '组件更新之前')
    }

    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log("componentDidUpdate", '组件更新完毕')
    }

    UNSAFE_componentWillReceiveProps(nextProps, nextContext) {
        console.log('componentWillReceiveProps', this.props, nextProps,"接受最新属性之前")
    }
}

console.dir(Vote)

export default Vote


// ES5 完成继承
function AAA() {
    React.Component.call(this)
    this.state = {x: 10, y: 20}
}

Object.setPrototypeOf(AAA.prototype, React.Component.prototype)
// AAA.prototype.sum = function(){...}